home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / launchpad-integration / launchpadintegration / packageinfo.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  11KB  |  310 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. '''
  5. Code used to identify a package based on one of the following:
  6.  * A process ID
  7.  * A file name
  8.  * A desktop file
  9.  * A binary package name
  10. '''
  11. import sys
  12. import os
  13. import socket
  14. import subprocess
  15. DPKGDIR = '/var/lib/dpkg'
  16. INFODIR = os.path.join(DPKGDIR, 'info')
  17. STATUSFILE = os.path.join(DPKGDIR, 'status')
  18.  
  19. class PackageNotFoundError(Exception):
  20.     pass
  21.  
  22.  
  23. def _get_pkg(filename):
  24.     """Find the binary package associated with the given filename
  25.  
  26.     This scans the list files in /var/lib/dpkg/info, since it is faster
  27.     than 'dpkg-query -S'.
  28.     """
  29.     for listfile in os.listdir(INFODIR):
  30.         if not listfile.endswith('.list'):
  31.             continue
  32.         
  33.         contents = open(os.path.join(INFODIR, listfile), 'r').read()
  34.         if filename in contents.splitlines(False):
  35.             return listfile[:-len('.list')]
  36.             continue
  37.     
  38.  
  39.  
  40. class PackageInfo(object):
  41.     
  42.     def __init__(self, binarypackage, sourcepackage, provides, version, architecture, status, dependencies):
  43.         self.binarypackage = binarypackage
  44.         if not sourcepackage:
  45.             pass
  46.         self.sourcepackage = binarypackage
  47.         self.provides = set(provides)
  48.         self.version = version
  49.         self.architecture = architecture
  50.         self.status = status
  51.         self.dependencies = set(dependencies)
  52.         self.names = set(self.provides)
  53.         self.names.add(self.binarypackage)
  54.  
  55.     
  56.     def installed(self):
  57.         if self.status:
  58.             state = self.status.split()[2]
  59.             return state not in ('config-files', 'not-installed')
  60.         else:
  61.             return False
  62.  
  63.     installed = property(installed)
  64.     
  65.     def shortstatus(self):
  66.         if self.status:
  67.             sinfo = self.status.split()
  68.             return sinfo[0][0] + sinfo[2][0]
  69.         else:
  70.             return None
  71.  
  72.     shortstatus = property(shortstatus)
  73.     
  74.     def __repr__(self):
  75.         return "<PackageInfo '%s_%s_%s'>" % (self.binarypackage, self.version, self.architecture)
  76.  
  77.     
  78.     def fromXID(cls, xid = None, logger = None):
  79.         """Return a PackageInfo instance corresponding to a window
  80.  
  81.         This is performed by calling xprop to get WM_CLIENT_MACHINE
  82.         and _NET_WM_PID properties of a window.  If WM_CLIENT_MACHINE
  83.         is our hostname, and _NET_WM_PID is set, then chain to
  84.         fromProcessID().
  85.  
  86.         If no XID is passed, xprop works in 'picker' mode.
  87.         """
  88.         cmdline = [
  89.             'xprop',
  90.             '-notype']
  91.         if xid is not None:
  92.             cmdline.extend([
  93.                 '-id',
  94.                 str(xid)])
  95.         
  96.         cmdline.extend([
  97.             'WM_CLIENT_MACHINE',
  98.             '_NET_WM_PID'])
  99.         if logger:
  100.             logger.debug('Executing %r', cmdline)
  101.         
  102.         
  103.         try:
  104.             p = subprocess.Popen(cmdline, stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True)
  105.             (stdout, stderr) = p.communicate()
  106.             result = p.returncode
  107.         except (OSError, IOError):
  108.             if logger:
  109.                 logger.exception('Could not find process ID')
  110.             
  111.             raise PackageNotFoundError('Could not find process ID')
  112.  
  113.         if result != 0:
  114.             raise PackageNotFoundError('Could not find process ID')
  115.         
  116.         props = dict((lambda .0: for x in .0:
  117. x.split(' = ', 1))(stdout.splitlines(False)))
  118.         if logger:
  119.             logger.debug('WM_CLIENT_MACHINE = %s, _NET_WM_PID = %s', props.get('WM_CLIENT_MACHINE'), props.get('_NET_WM_PID'))
  120.         
  121.         hostname = '"%s"' % socket.gethostname()
  122.         if props.get('WM_CLIENT_MACHINE', hostname) != hostname or '_NET_WM_PID' not in props:
  123.             raise PackageNotFoundError('Could not find process ID')
  124.         
  125.         
  126.         try:
  127.             pid = int(props['_NET_WM_PID'])
  128.         except ValueError:
  129.             raise PackageNotFoundError('Could not find process ID')
  130.  
  131.         if logger:
  132.             logger.info('Process ID for selected window is %d', pid)
  133.         
  134.         return cls.fromProcessID(pid, logger)
  135.  
  136.     fromXID = classmethod(fromXID)
  137.     
  138.     def fromProcessID(cls, pid, logger = None):
  139.         '''Return a PackageInfo instance corresponding to a process ID
  140.  
  141.         This is performed by looking up the executable name in the /proc
  142.         filesystem, then chaining to fromFilename().
  143.         '''
  144.         if logger:
  145.             logger.debug('Looking up executable for process %d', pid)
  146.         
  147.         
  148.         try:
  149.             filename = os.readlink('/proc/%d/exe' % pid)
  150.         except OSError:
  151.             if logger:
  152.                 logger.exception('Could not find executable for process %d', pid)
  153.             
  154.             raise PackageNotFoundError('Could not find executable for process %d' % pid)
  155.  
  156.         if filename.endswith(' (deleted)'):
  157.             logger.error('Process %d is running deleted executable "%s"', pid, filename)
  158.             raise PackageNotFoundError('Process %d is running deleted executable "%s"' % (pid, filename))
  159.         
  160.         if logger:
  161.             logger.info('Executable for process %d is "%s"', pid, filename)
  162.         
  163.         if filename.startswith('/rofs'):
  164.             filename = filename[len('/rofs'):]
  165.         elif filename.startswith('/filesystem.squashfs'):
  166.             filename = filename[len('/filesystem.squashfs'):]
  167.         
  168.         return cls.fromFilename(filename, logger)
  169.  
  170.     fromProcessID = classmethod(fromProcessID)
  171.     
  172.     def fromDesktopFile(cls, filename, logger = None):
  173.         """Return a PackageInfo instance corresponding to a Desktop file
  174.  
  175.         This is performed by looking for the executable name in the 'exec'
  176.         line of the desktop file, then chains to fromFilename().
  177.  
  178.         This function should be used instead of fromFilename() because
  179.         the desktop file might be a customised one in the user's home
  180.         directory, but still points to an installed application.
  181.         """
  182.         raise NotImplementedError
  183.  
  184.     fromDesktopFile = classmethod(fromDesktopFile)
  185.     
  186.     def fromFilename(cls, filename, logger = None):
  187.         '''Return a PackageInfo instance corresponding to a file
  188.  
  189.         This is performed by finding the package that owns the file
  190.         using dpkg-query, and then chaining to fromPackageName to
  191.         fill in the PackageInfo instance.
  192.         '''
  193.         if logger:
  194.             logger.debug('Looking up binary package name for file "%s"', filename)
  195.         
  196.         
  197.         try:
  198.             package = _get_pkg(filename)
  199.         except (OSError, IOError):
  200.             if logger:
  201.                 logger.exception('Could not find binary package for file "%s"', filename)
  202.             
  203.             raise PackageNotFoundError('Could not find binary package for file "%s"' % filename)
  204.  
  205.         if package is None:
  206.             raise PackageNotFoundError('Could not look up binary package for file "%s"' % filename)
  207.         
  208.         if logger:
  209.             logger.info('Binary package for file "%s" is "%s"', filename, package)
  210.         
  211.         return cls.fromPackageName(package, logger)
  212.  
  213.     fromFilename = classmethod(fromFilename)
  214.     
  215.     def fromPackageName(cls, package, logger = None):
  216.         '''Return a PackageInfo instance for a particular binary package name
  217.         '''
  218.         if logger:
  219.             logger.debug('Looking up package information for "%s"', package)
  220.         
  221.         for info in cls._iterPackages():
  222.             if package in info.names:
  223.                 break
  224.                 continue
  225.         else:
  226.             raise PackageNotFoundError('Could not look up package info for "%s"' % package)
  227.         if logger:
  228.             logger.debug('Package info for %s is %r', package, info)
  229.         
  230.         return info
  231.  
  232.     fromPackageName = classmethod(fromPackageName)
  233.     
  234.     def fromPackageNames(cls, packages, logger = None):
  235.         '''Iterate through PackageInfo instances that match names in packages.
  236.  
  237.         This is an optimisation of fromPackageName() for when you want
  238.         multiple packages.
  239.         '''
  240.         packages = set(packages)
  241.         for info in cls._iterPackages():
  242.             if packages & info.names:
  243.                 if logger:
  244.                     logger.debug('Package %r matched', info)
  245.                 
  246.                 yield info
  247.                 continue
  248.         
  249.  
  250.     fromPackageNames = classmethod(fromPackageNames)
  251.     
  252.     def _iterPackages(cls, filename = STATUSFILE):
  253.         '''Iterate through the list of packages in the DPKG database'''
  254.         package = None
  255.         status = None
  256.         architecture = None
  257.         source = None
  258.         version = None
  259.         provides = []
  260.         dependencies = []
  261.         for line in open(filename, 'r'):
  262.             if line == '\n':
  263.                 yield cls(binarypackage = package, sourcepackage = source, provides = provides, version = version, architecture = architecture, status = status, dependencies = dependencies)
  264.                 package = None
  265.                 status = None
  266.                 architecture = None
  267.                 source = None
  268.                 version = None
  269.                 provides = []
  270.                 dependencies = []
  271.                 continue
  272.             if line.startswith('Package: '):
  273.                 package = line[len('Package: '):].strip()
  274.                 continue
  275.             if line.startswith('Status: '):
  276.                 status = line[len('Status: '):].strip()
  277.                 continue
  278.             if line.startswith('Architecture: '):
  279.                 architecture = line[len('Architecture: '):].strip()
  280.                 continue
  281.             if line.startswith('Source: '):
  282.                 source = line[len('Source: '):].strip()
  283.                 continue
  284.             if line.startswith('Version: '):
  285.                 version = line[len('Version: '):].strip()
  286.                 continue
  287.             if line.startswith('Provides: '):
  288.                 provides.extend((lambda .0: for x in .0:
  289. x.strip())(line[len('Provides: '):].split(', ')))
  290.                 continue
  291.             if line.startswith('Depends: '):
  292.                 deps = line[len('Depends: '):].strip()
  293.                 dependencies.extend((lambda .0: for x in .0:
  294. for y in x.split('|'):
  295. y.split()[0])(deps.split(', ')))
  296.                 continue
  297.             if line.startswith('Pre-Depends'):
  298.                 deps = line[len('Pre-Depends: '):].strip()
  299.                 dependencies.extend((lambda .0: for x in .0:
  300. for y in x.split('|'):
  301. y.split()[0])(deps.split(', ')))
  302.                 continue
  303.         
  304.         if package is not None:
  305.             yield cls(binarypackage = package, sourcepackage = source, provides = provides, version = version, architecture = architecture, status = status, dependencies = dependencies)
  306.         
  307.  
  308.     _iterPackages = classmethod(_iterPackages)
  309.  
  310.